
`include "defines.v"

module ctr_cpu (
    input  wire              rst,
    
    input  wire [4 :      0] op,
    input  wire [2 :      0] f3,
    input  wire              f7,
    
    input  wire              zero,
    input  wire [`BUS_WIDTH] result,

    output reg  [2 :      0] ext_op,
    output reg               reg_wen,
    output reg  [3 :      0] alu_ctr,
    output reg               mem_ren,    
    output reg               mem_wen,
    output reg               alu_asrc,
    output reg  [1 :      0] alu_bsrc,
    output reg               mem2reg,
    output reg  [1 :      0] pc_sel,
    output reg  [2 :      0] width_sel
);
    

    always @(*) begin
        if (rst) begin
            ext_op    = 3'b000;
            reg_wen   = 1'b0;
            alu_ctr   = 4'b0000;
            mem_ren   = 1'b0;
            mem_wen   = 1'b0;
            alu_asrc  = 1'b0;
            alu_bsrc  = 2'b00;
            mem2reg   = 1'b0;
            pc_sel    = 2'b00;
            width_sel = 3'b000;
        end
        else begin
            case (op)
                5'b01100: begin
                    ext_op    = 3'b111;    // 可取任意值
                    reg_wen   = 1'b1;
                    mem_ren   = 1'b0;
                    mem_wen   = 1'b0;
                    alu_asrc  = 1'b0;
                    alu_bsrc  = 2'b00;
                    mem2reg   = 1'b0;
                    pc_sel    = 2'b00;
                    width_sel = 3'b011;
                    case (f3)
                        3'b001: begin    // sll
                            alu_ctr = 4'b0001;
                        end
                        3'b101: begin    // sra, srl
                            alu_ctr = (f7) ? 4'b0101 : 4'b0100;
                        end
                        3'b000: begin    // sub, add
                            alu_ctr = (f7) ? 4'b1000 : 4'b0000;
                        end
                        3'b100: begin    // xor
                            alu_ctr = 4'b0111;
                        end
                        3'b110: begin    // or
                            alu_ctr = 4'b0110;
                        end
                        3'b111: begin    // and
                            alu_ctr = 4'b1001;
                        end
                        3'b010: begin    // slt
                            alu_ctr = 4'b0010;
                        end
                        3'b011: begin    // sltu
                            alu_ctr = 4'b0011;
                        end
                    endcase
                end
                5'b00100: begin
                    reg_wen   = 1'b1;
                    mem_ren   = 1'b0;
                    mem_wen   = 1'b0;
                    alu_asrc  = 1'b0;
                    alu_bsrc  = 2'b10;
                    mem2reg   = 1'b0;
                    pc_sel    = 2'b00;
                    width_sel = 3'b011;
                    case (f3)
                        3'b001: begin    // slli
                            ext_op  = 3'b000;
                            alu_ctr = 4'b0001;
                        end
                        3'b101: begin    // srai,srli
                            ext_op  = 3'b000;
                            alu_ctr = (f7) ? 4'b0101 : 4'b0100;
                        end
                        3'b000: begin    // addi
                            ext_op  = 3'b000;
                            alu_ctr = 4'b0000;
                        end
                        3'b100: begin    // xori
                            ext_op  = 3'b000;
                            alu_ctr = 4'b0111;
                        end
                        3'b110: begin    // ori
                            ext_op  = 3'b000;
                            alu_ctr = 4'b0110;
                        end
                        3'b111: begin    // andi
                            ext_op  = 3'b000;
                            alu_ctr = 4'b1001;
                        end
                        3'b010: begin    // slti
                            ext_op  = 3'b000;
                            alu_ctr = 4'b0010;
                        end
                        3'b011: begin    // sltiu
                            ext_op  = 3'b000;
                            alu_ctr = 4'b0011;
                        end
                    endcase
                end
                5'b01110: begin
                    ext_op    = 3'b111;    // 可取任意值
                    reg_wen   = 1'b1;
                    mem_ren   = 1'b0;
                    mem_wen   = 1'b0;
                    alu_asrc  = 1'b0;
                    alu_bsrc  = 2'b00;
                    mem2reg   = 1'b0;
                    pc_sel    = 2'b00;
                    width_sel = 3'b010;
                    case (f3)
                        3'b001: begin    // sllw
                            alu_ctr = 4'b1010;
                        end
                        3'b101: begin    // sraw, srlw
                            alu_ctr = (f7) ? 4'b1100 : 4'b1011;
                        end
                        3'b000: begin    // subw, addw
                            alu_ctr = (f7) ? 4'b1000 : 4'b0000;
                        end
                        default: begin
                            alu_ctr = 4'b0000;
                        end
                    endcase
                end
                5'b00110: begin
                    reg_wen   = 1'b1;
                    mem_ren   = 1'b0;
                    mem_wen   = 1'b0;
                    alu_asrc  = 1'b0;
                    alu_bsrc  = 2'b10;
                    mem2reg   = 1'b0;
                    pc_sel    = 2'b00;
                    width_sel = 3'b010;
                    case (f3)
                        3'b001: begin    // slliw
                            ext_op  = 3'b000;
                            alu_ctr = 4'b1010;
                        end
                        3'b101: begin    // sraiw, srliw
                            ext_op  = 3'b000;
                            alu_ctr = (f7) ? 4'b1100 : 4'b1011;
                        end
                        3'b000: begin    // addiw
                            ext_op  = 3'b000;
                            alu_ctr = 4'b0000;
                        end
                        default: begin
                            ext_op  = 3'b111;
                            alu_ctr = 4'b0000;
                        end
                    endcase
                end
                5'b01101: begin    // lui
                    ext_op    = 3'b001;
                    reg_wen   = 1'b1;
                    alu_ctr   = 4'b1111;
                    mem_ren   = 1'b0;
                    mem_wen   = 1'b0;
                    alu_asrc  = 1'b0;    // 可取任意值
                    alu_bsrc  = 2'b10;
                    mem2reg   = 1'b0;
                    pc_sel    = 2'b00;
                    width_sel = 3'b011;
                end
                5'b00101: begin    // auipc
                    ext_op    = 3'b001;
                    reg_wen   = 1'b1;
                    alu_ctr   = 4'b0000;
                    mem_ren   = 1'b0;
                    mem_wen   = 1'b0;
                    alu_asrc  = 1'b1;
                    alu_bsrc  = 2'b10;
                    mem2reg   = 1'b0;
                    pc_sel    = 2'b00;
                    width_sel = 3'b011;
                end
                5'b11000: begin    // Branches
                    ext_op    = 3'b011;
                    reg_wen   = 1'b0;
                    mem_ren   = 1'b0;
                    mem_wen   = 1'b0;
                    alu_asrc  = 1'b0;
                    alu_bsrc  = 2'b00;
                    mem2reg   = 1'b0;      // 可取任意值
                    width_sel = 3'b011;    // 可取任意值
                    case (f3)
                        3'b000: begin    // beq
                            alu_ctr = 4'b1000;
                            pc_sel  = ( zero     ) ? 2'b01 : 2'b00;
                        end
                        3'b001: begin    // bne
                            alu_ctr = 4'b1000;
                            pc_sel  = (~zero     ) ? 2'b01 : 2'b00;
                        end
                        3'b100: begin    // blt
                            alu_ctr = 4'b0010;
                            pc_sel  = ( result[0]) ? 2'b01 : 2'b00;
                        end
                        3'b101: begin    // bge
                            alu_ctr = 4'b0010;
                            pc_sel  = (~result[0]) ? 2'b01 : 2'b00;
                        end
                        3'b110: begin    // bltu
                            alu_ctr = 4'b0011;
                            pc_sel  = ( result[0]) ? 2'b01 : 2'b00;
                        end
                        3'b111: begin    // bgeu
                            alu_ctr = 4'b0011;
                            pc_sel  = (~result[0]) ? 2'b01 : 2'b00;
                        end
                        default: begin
                            alu_ctr = 4'b0000;
                            pc_sel  = 2'b00;
                        end
                    endcase
                end
                5'b11011: begin    // jal
                    ext_op    = 3'b100;
                    reg_wen   = 1'b1;
                    alu_ctr   = 4'b0000;
                    mem_ren   = 1'b0;
                    mem_wen   = 1'b0;
                    alu_asrc  = 1'b1;
                    alu_bsrc  = 2'b01;
                    mem2reg   = 1'b0;
                    pc_sel    = 2'b01;
                    width_sel = 3'b011;
                end
                5'b11001: begin    // jalr
                    ext_op    = 3'b000;
                    reg_wen   = 1'b1;
                    alu_ctr   = 4'b0000;
                    mem_ren   = 1'b0;
                    mem_wen   = 1'b0;
                    alu_asrc  = 1'b1;
                    alu_bsrc  = 2'b01;
                    mem2reg   = 1'b0;
                    pc_sel    = 2'b10;
                    width_sel = 3'b011;
                end
                5'b00000: begin    // Loads
                    ext_op    = 3'b000;
                    reg_wen   = 1'b1;
                    alu_ctr   = 4'b0000;
                    mem_ren   = 1'b1;
                    mem_wen   = 1'b0;
                    alu_asrc  = 1'b0;
                    alu_bsrc  = 2'b10;
                    mem2reg   = 1'b1;
                    pc_sel    = 2'b00;
                    width_sel = f3;
                end
                5'b01000: begin    // Stores
                    ext_op    = 3'b010;
                    reg_wen   = 1'b0;
                    alu_ctr   = 4'b0000;
                    mem_ren   = 1'b0;
                    mem_wen   = 1'b1;
                    alu_asrc  = 1'b0;
                    alu_bsrc  = 2'b10;
                    mem2reg   = 1'b0;    // 可取任意值
                    pc_sel    = 2'b00;
                    width_sel = f3;
                end
                /* 5'b11010: begin    // 输出a0寄存器的值(自定义)
                    ext_op    = 3'b000;
                    reg_wen   = 1'b0;
                    alu_ctr   = 4'b1111;
                    mem_ren   = 1'b0;
                    mem_wen   = 1'b0;
                    alu_asrc  = 1'b0;
                    alu_bsrc  = 2'b00;
                    mem2reg   = 1'b0;      // 可取任意值
                    pc_sel    = 2'b00;
                    width_sel = 3'b000;    // 可取任意值
                    $write("%s", result);
                end */
                default: begin
                    ext_op    = 3'b111;
                    reg_wen   = 1'b0;
                    alu_ctr   = 4'b000;
                    mem_ren   = 1'b0;
                    mem_wen   = 1'b0;
                    alu_asrc  = 1'b0;
                    alu_bsrc  = 2'b00;
                    mem2reg   = 1'b0;
                    pc_sel    = 2'b00;
                    width_sel = 3'b011;
                end
            endcase
        end
    end


endmodule
              